<?php
/*
 * ==BeLean==
 * This file is part of the BeLean project!
 * 
 * BBS Brinkstrasse Osnabrück
 * @author	Marco Kreienbrink <marco.kreienbrink@googlemail.com>
 *  
 */
 
 include_once "basic.class.php";
 
 class form extends basic{
 	private $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
	private $tokenTable = "token";
	private $questionTable = "question";
	private $formTable = "form";
	private $answerTable = "answer";
	private $form2teacherTable = "teacher_form";
	private $oDB;
	private $retry;
	private $iTeacher;
	
 	function __construct(&$config){
		parent::__construct($config);
 	}
	
	/**
	 * Sets the database Object for further use
	 * 
	 * @param object $oDB DatabaseObject
	 */
	function setDB(&$oDB){
		if(is_object($oDB)){
			$this->oDB = $oDB;
		}
	}
	
	/**
	 * Controlls if a given Teacher has the right to manipulate a certain form
	 * 
	 * @param int $iTeacher
	 * @param int $iForm
	 */
	function teacherIsOwner($iTeacher,$iForm){
		$sSQL = "SELECT count(*) as num from ".$this->formTable." where id = $iForm and teacher_id = $iTeacher";
		$this->oDB->executeQuery($sSQL);
		$ret = $this->oDB->getRow();
		if($ret['num']==1){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Controlls if the passed parameter is a valid number and calls the function for creating a Token.
	 * The Tokens are then stored in an array
	 * 
	 * @param int $iCount
	 * @param int $iFormIf
	 * @param string $sClass
	 * @return array $aTokens
	 */
	function getToken($iCount, $iFormId, $sClass=""){
		if(is_int($iCount) && $iCount > 0){
			$this->retry=0;
			for($i=0; $i<$iCount;$i++){
				$aToken[] = $this->createToken();
			}
			$this->saveToken($aToken, $iFormId, $sClass);
		}
	}	
	
	/**
	 * Function to create a random Token.
	 * Once a token has ben generated, the function will controll if there is already one identical Token in the database
	 * 
	 * @return string Token
	 */
	private function createToken(){
		$charLength = strlen($this->chars)-1;
		$sToken ="";
	    for($i = 0 ; $i < $this->oConfig->getValue('tokenLength') ; $i++){
	            $sToken .= $this->chars[mt_rand(0,$charLength)];
        }
		if($this->tokenExists($sToken) && $this->retry<$this->oConfig->getValue('retryBevoreAbort')){
			$this->retry++;
			$this->createToken();
		}else{
	    	return $sToken;
		}
	}
	
	/**
	 * Function to controll if a given Token is already present in the Database.
	 * Return true if the Token is already present in the database
	 * 
	 * @param string $sToken
	 * @return bool
	 */
	function tokenExists($sToken){
		$sSQL = "SELECT * from ".$this->tokenTable." where token = '".$this->oDB->dbEscapeString($sToken)."'";		
		$this->oDB->executeQuery($sSQL);
		if(($aToken = $this->oDB->getRow()) !== false){
			if(trim($aToken['teacher_id'])!="" && trim($aToken['teacher_id'])!="0"){
				$this->iTeacher = $aToken['teacher_id'];
				$_SESSION['user_id'] = $aToken['teacher_id'];
			}elseif($aToken['used']==0){
				$_SESSION['form'] = $aToken['form_id'];
				$this->iTeacher = false;
			}else{
				return false;
			}
			return true;
		}		
	}
	
	/**
	 * Function to save a variable number of Tokens in to the database
	 * 
	 * @param string Class
	 * @param $aToken array with all Token to save
	 * @return bool
	 */
	function saveToken($aToken, $iFormId, $sClass){
		$sSQL = "INSERT into ".$this->tokenTable."(token, class, form_id) values";
		if(is_array($aToken) && count($aToken)>0){
			$iCount = count($aToken);
			$iC = 0;
			for($i=0; $i<count($aToken); $i++){
				$sSQL .= "('".$aToken[$i]."','$sClass', '$iFormId')";
				if($i< (count($aToken)-1)){
					$sSQL .= ",";
				}				
			}
		}else{
			$sSQL .= "('$aToken','$sClass', '$iFormId')";
		}
		$this->oDB->executeUpdate($sSQL);
		if($this->oDB->getNumRow()>0){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Function to controll if a given Token is a valid one
	 * This is just a wrapper for the tokenExists Functon in case that some day there should change how Tokens will be stored
	 * in example one more field to hold if a given Token has already been used or not.
	 * 
	 * @param string $sToken
	 * @return bool
	 */
	function isValidToken($sToken){
		return $this->tokenExists($sToken);
	}	
	
	/**
	 * Controlls if a given Token is a teachers Token or not
	 * 
	 * @param int $iToken 
	 * @return bool true|false 
	 */
	function isTeacherToken($iToken){
		if($this->iTeacher !== false && !$this->iTeacher){
			$this->tokenExists($iToken);
		}	
		if($this->iTeacher !== false){
			return true;
		}else{				
			return false;
		}
	}
	
	/**
	 * Deletes a given Token.
	 * To use when a User has finished and sent a Form.
	 * 
	 * @param string $sToken 
	 */
	function deleteToken($sToken){
		if(trim($sToken)!==""){
			$sSQL = "DELETE from ".$this->tokenTable." where token ='$sToken'";
			$this->oDB->executeUpdate($sSQL);
		}
	}
	
	/**
	 * Returns the number of Token already created for a given Form
	 * @param int $iFormId
	 * @return int $iAmmount
	 */
	function getNumTokensByForm($iFormId){
		$sSQL = "SELECT count(*) ammount from ".$this->tokenTable." where form_id = $iFormId and teacher_id = 0";
		$this->oDB->executeQuery($sSQL);
		$res = $this->oDB->getRow();
		return $res['ammount'];
	}
	
	/**
	 * Returns alle the Tokens by a formid
	 * @param int $iFormId
	 * @return array Tokens
	 */
	function getTokenByForm($iFormId){
		$sSQL = "SELECT * from ".$this->tokenTable." where form_id = $iFormId and teacher_id = 0";		
		$this->oDB->executeQuery($sSQL);
		return $this->oDB->getRows();
	}
	
	/**
	 * Adds a given Question to the Questionpool
	 * Returns true if the Question has been added to the Database or false if not
	 * 
	 * @param string $sQuestion
	 * @param int $iFormId
	 * @return bool
	 */
	function addQuestion($sQuestion, $iFormId){
		if($this->userIsOwnerOfForm($_SESSION['user_id'], $iFormId)){
			$sSQL = "INSERT into ".$this->questionTable."(question, form_id) values ('".$this->oDB->dbEscapeString($sQuestion)."', $iFormId)";
			$this->oDB->executeUpdate($sSQL);
			if($this->oDB->getNumRow()>0){
				return true;
			}else{
				return false;
			}
		}
	}
	
	/**
	 * Function to alter a Question. Attention! Questions will be editable only until they're asigned to a Form!
	 * Once a question has been asigned it wont be editable anymore!
	 * 
	 * @param string $sQuestion
	 * @return bool
	 */
	function alterQuestion($sQuestion, $iId){
		$sSQL = "UPDATE ".$this->questionTable." set question = '".$this->oDB->dbEscapeString($sQuestion)."' where id = $iId and published = 0";
		$this->oDB->executeUpdate($sSQL);
		if($this->oDB->getNumRow()>0){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Deletes a given Question.
	 * Attention! Once a Question has been added to a Form it wont be editable anymore!
	 * 
	 * @param int $iId
	 * @return bool
	 */
	function deleteQuestion($iId, $force=false){
		$sSQL = "DELETE from ".$this->questionTable." where id = $iId";
		if(!$force){
			$sSQL .= "&& published = 0";
		}	
		$this->oDB->executeUpdate($sSQL);
		if($this->oDB->getNumRow()>0){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Retrieves a Question by its Id
	 * 
	 * @param int $iId
	 * @return string $sQuestion 
	 */
	function getQuestionById($iId){
		if(is_numeric($iId)){
			$sSQL = "SELECT question from ".$this->questionTable." where id = $iId";
			$this->oDB->executeQuery($sSQL);
			$question = $this->oDB->getRow();
			return $question['question'];
		}
	}
	
	/**
	 * This function retrieves every Question by a given Form.
	 * The array will be constructed as follows:
	 *  $array[question_id] = $question
	 * 
	 * @param int $iFormId
	 * $return array Result
	 */
	function getQuestionsByFormNorm($iFormId){
		$sSQL ="SELECT * from ".$this->questionTable." where form_id = $iFormId";		
		$this->oDB->executeQuery($sSQL);
		return $this->oDB->getRows();
	}
	
	function getQuestionsByForm($iFormId){
		$sSQL ="SELECT * from ".$this->questionTable." where form_id = $iFormId";		
		$this->oDB->executeQuery($sSQL);
		//return $this->oDB->getRows();
		$ret="";
		while ($row = mysql_fetch_assoc($this->oDB->returnResult())) {
		    $ret[$row['id']] = $row['question'];
		}
		return $ret;
	}
	
	/**
	 * Retrieves all the Questions from a given teacher
	 * 
	 * @param int $iTeacherId
	 * @return array mixed
	 */
	function getQuestionByTeacher($iTeacherId){
		$sSQL = "SELECT * from ".$this->questionTable." inner join form where form.teacher_id = $iTeacherId and form.id = question.form_id";
		$this->oDB->executeQuery($sSQL);
		$aResult = $this->oDB->getRows();
		print_r($aResult);
	}
	
	/**
	 * Returns all the forms o a teacher
	 * 
	 * @param int $iTeacherId
	 * @return array mixed
	 */
	function getFormsByTeacher($iTeacherId){		
		$sSQL = "SELECT * from ".$this->formTable." where teacher_id = $iTeacherId";	
		$this->oDB->executeQuery($sSQL);
		return $this->oDB->getRows();
	}
	
	/**
	 * Returns all the Details about a given Form
	 */
	function getFormDetails($iFormId){
		$sSQL = "SELECT * from ".$this->formTable." where id = $iFormId";
		$this->oDB->executeQuery($sSQL);
		return $this->oDB->getRow();
	}
	
	function getFormByQuestionId($iQuestionId){
		$sSQL = "SELECT form_id from ".$this->questionTable." where id=$iQuestionId";
		$this->oDB->executeQuery($sSQL);
		$res = $this->oDB->getRow();
		return $res['form_id'];
	}
	
	/**
	 * Returns the number of questions of a given form
	 * 
	 * @param int $iFormId
	 * @return int 
	 */
	function getNumQuestionsForForm($iFormId){
		$sSQL ="SELECT count(*) as cnt from ".$this->questionTable." where form_id = $iFormId";
		$this->oDB->executeQuery($sSQL);
		$res = $this->oDB->getRow();
		return $res['cnt'];
	}
	
	/**
	 * Creates a new empty form and returns the form_id
	 * 
	 * @param string $sName
	 * @param int $iTeacherId
	 * @return int $iFormId
	 */
	function createForm($sName, $iTeacherId, $sDescription=""){
		$sSQL = "INSERT into ".$this->formTable." (name,teacher_id, description) values('".$this->oDB->dbEscapeString($sName)."',$iTeacherId,";
		if($sDescription!=""){
			$sSQL .= "'".$this->oDB->dbEscapeString($sDescription)."'";
		}else{
			$sSQL .= "''";
		}
		$sSQL .= ")";
		$this->oDB->executeUpdate($sSQL);
		$iFormId = $this->oDB->getLastInsertId();
		$sSQL = "INSERT into ".$this->form2teacherTable." (form_id,teacher_id) values($iFormId,$iTeacherId)";
		$this->oDB->executeUpdate($sSQL);
		return $iFormId;
	}
	
	/**
	 * Clones a complete Form, with all the questions.
	 * 
	 * @param int $iFormId ID of the form to be cloned
	 */
	function cloneForm($iFormId, $iUserId=""){
		if($iUserId=="")$iUserId=$_SESSION['user_id'];
		$sSQL = "SELECT name,description from ".$this->formTable." where id = $iFormId";
		$this->oDB->executeQuery($sSQL);
		$aFormData = $this->oDB->getRows();
		$iNewFormId = $this->createForm($aFormData[0]['name'], $iUserId, $aFormData[0]['description']);
		$aQuestions = $this->getQuestionsByForm($iFormId);
		$sSQL = "INSERT into ".$this->questionTable." (question,form_id) values";
		$iCount = 1;
		foreach($aQuestions as $k=>$v){
			$sSQL .= "('".$v."',$iNewFormId)";
			$iCount<count($aQuestions)?$sSQL.=",":"";
			$iCount++;
		}
		$this->oDB->executeUpdate($sSQL);
	}
	
	/**
	 * This will delete the form and all the assosiated questions
	 * 
	 * @param int $iFormId
	 */
	function deleteForm($iFormId){
		if($this->userIsOwnerOfForm($_SESSION['user_id'], $iFormId)){
			$aQuestions = $this->getQuestionsByForm($iFormId);
/*			if(is_array($aQuestions) && count($aQuestions) > 0){
				for($i=0; $i < count($aQuestions); $i++){
					$this->deleteQuestion($aQuestions[$i]['id'],true);	
				}			
			}
 */ 
			$sSQL = "DELETE from ".$this->formTable." where id = $iFormId";
			$this->oDB->executeUpdate($sSQL);
		}
	}
	
	function editForm($sName, $iFormId, $sDescription=""){
		if($this->userIsOwnerOfForm($_SESSION['user_id'], $iFormId)){
			$sSQL = "UPDATE ".$this->formTable." set name='$sName', description='$sDescription' where id=$iFormId";			
			$this->oDB->executeUpdate($sSQL);
			if($this->oDB->getNumRow()>0){
				return true;
			}else{
				return false;
			}
		}
	}
	
	/**
	 * Marks all the questions related to a given form a s published, so that they wont be editable anymore
	 * 
	 * @param int $iFormId
	 */
	function publishForm($iFormId){
		if($this->userIsOwnerOfForm($_SESSION['user_id'], $iFormId)){
			$sSQL = "UPDATE ".$this->formTable." set published = 1 where id = $iFormId";
			$this->oDB->executeUpdate($sSQL);
			if($this->oDB->getNumRow()>0){
				return true;
			}else{
				return false;
			}
		}
	}
	
	/**
	 * Saves one or more Answers with all the needed data
	 * Returns true if the Answer has been saved sucesfully
	 * The answer array has to be in the following format:
	 * $array[$questionId] = $answer
	 * 
	 * @param string $sToken
	 * @param int $iFormId
	 * @param array $aAnswer 
	 * @return bool
	 */
	 function saveAnswer($sToken, $iFormId, $aData){
		if(is_array($aData) && count($aData)>0){
			$sSQL = "INSERT into ".$this->answerTable."(form_id, question_id, token, time, answer, teacher_id, typ) values";
			$iCount = 0;		
			for($i=0; $i<count($aData); $i++){							
				$sSQL .= "($iFormId, ".$aData[$i][0].", '$sToken',NOW(), '".$this->oDB->dbEscapeString($aData[$i][3])."', ".$aData[$i][1].", '".$aData[$i][2]."')";
				if($iCount<(count($aData)-1)){
					$sSQL .=",";
				}
				$iCount++;
			}	
			$this->oDB->executeUpdate($sSQL);
			if($this->oDB->getNumRow()>0){
				$this->setTokenAsUsed($sToken);
				return true;
			}else{
				return false;
			}
		}	
	}

	/**
	 * Sets a Token as used
	 * 
	 * @param string $sToken
	 */
	function setTokenAsUsed($sToken){
		$sSQL = "UPDATE ".$this->tokenTable." set used  = 1 where token = '$sToken'";
		$this->oDB->executeUpdate($sSQL);		
	}
	
	/**
	 * Returns the number of answers that have been saved already
	 * 
	 * @param int $iFormid
	 * @return int $iNumberOfAnswers
	 */	
	function getNumAnswers($iFormId){	
		$sSQL = "SELECT count(distinct token) numAnswers from ".$this->answerTable." where form_id = $iFormId";
		$this->oDB->executeQuery($sSQL);
		$res = $this->oDB->getRow();
		return $res['numAnswers'];
	}
		 
	/** 
	 * return true if the Form is already published
	 * 
	 * @param int $iFormId
	 */
	function formIsPublished($iFormId){
	 	$sSQL = "SELECT published from ".$this->formTable." where id = $iFormId";
		$this->oDB->executeQuery($sSQL);
		$res = $this->oDB->getRow();
		if($res['published']==1){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Returns true if the user is owner of the form
	 * 
	 * @param int $iUserId
	 * @param int $iFormId
	 * @return bool true|false
	 */
	function userIsOwnerOfForm($iUserId, $iFormId){
		$sSQL = "SELECT teacher_id from ".$this->form2teacherTable." where teacher_id = $iUserId and form_id = $iFormId";	
		$this->oDB->executeQuery($sSQL);
		$res = $this->oDB->getRow();
		if($res){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Returns the Name of the Class associated with a given Form
	 */
	function getClassByForm($iFormId){
		$sSQL = "SELECT class from ".$this->tokenTable." where form_id = $iFormId limit 1";
		$this->oDB->executeQuery($sSQL);
		$res = $this->oDB->getRow();
		if($res){
			return $res['class'];
		}else{
			return "";
		}
	}
	
	/**
	 * Calculates the result for all the answers of a given Form
	 * This function has already a second parameter $iTeacher, for the moment when it will be possible 
	 * to add more then one teacher to a given form
	 * 
	 * @param int $iFormId
	 * @param int $iFormid
	 * @return mixed array
	 */
	function getResults($iFormId,$iTeacherId=""){
		if($this->userIsOwnerOfForm($_SESSION['user_id'],$iFormId)){
			$sSQL = "select question_id,typ,round(AVG(answer),1) ans from ".$this->answerTable." where form_id = $iFormId group by question_id,typ";	
			$this->oDB->executeQuery($sSQL);
			//return $this->oDB->getRows();
			while ($row = mysql_fetch_assoc($this->oDB->returnResult())) {
			  $ret[$row['question_id']][$row['typ']] = $row['ans'];
			}
			return $ret;			
		}		
	}
	
	/**
	 * Returns the Results by each user and for each question
	 * 
	 * @param int $iFormId
	 * @return mixed array
	 */
	function getDistinctResults($iFormId){
		$sSQL = "SELECT question_id,token,typ,answer ans from ".$this->answerTable." where form_id = $iFormId 
				order by token, question_id";
		$this->oDB->executeQuery($sSQL);
		$i=0;
		while ($row = mysql_fetch_assoc($this->oDB->returnResult())) {
			if(isset($sTok) && $row['token']!=$sTok){
				$i++;
			}
		  	$ret[$i][$row['question_id']]['question_id'] = $row['question_id'];
		  	$ret[$i][$row['question_id']]['token'] = $row['token'];
			$ret[$i][$row['question_id']][$row['typ']] = $row['ans'];
			$sTok=$row['token'];	
		}	
		return $ret;
	}	
 }
?>